package model

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	uuid "github.com/satori/go.uuid"
	"io/ioutil"
	"time"
	"wall/app/config"
	"wall/app/utils"
)

/**
 * 构造函数, 得到实例
 */
func NewUser() *User {
	temp := &User{
		LoginData:      LoginData{},
		RegisterData:   RegisterData{},
		SecureCodeData: SecureCodeData{},
		VerifyCodeData: VerifyCodeData{},
	}

	return temp
}

/**
 * 登录验证
 */
func (u *User) login(cont string) (err error) {
	data := &u.LoginData

	config.GetLogger().Info("开始登录")

	user := new(Login)
	err = json.Unmarshal([]byte(cont), &user)
	if err != nil {
		config.GetLogger().Warnw("登录数据解析失败",
			"err", err.Error,
		)
		return err
	}

	//密码加密后验证
	tempPwd := md5.Sum([]byte(user.UserPassword))
	md5str := fmt.Sprintf("%x", tempPwd)

	userName := user.UserName
	userPwd := md5str

	//查询用户类型
	row := db.Table("user").Where("userName = ? AND userPwd = ?", userName, userPwd).Select("userType, ID").Row()

	err = row.Scan(&data.Type, &data.UserID)
	if err != nil {
		config.GetLogger().Warnw("用户名或密码错误",
			"err", err.Error,
		)
		return errors.New("用户名或密码错误")
	}

	config.GetLogger().Info("开始更新登录日志")

	i := new(LoginLogger)
	i.UserID = data.UserID
	i.UserName = user.UserName
	i.Time = time.Now().String()
	if err := db.Table("login").Create(i).Error; err != nil {
		config.GetLogger().Warnw("更新登录日志失败",
			"err", err,
		)
	}

	config.GetLogger().Info("更新登录日志结束")

	config.GetLogger().Info("登录成功")

	return
}

/**
 * 用户注册
 */
func (u *User) register(cont string) (err error) {
	count := 0
	data := &u.RegisterData

	config.GetLogger().Info("开始解析注册数据")
	loginReceive := new(Register)
	err = json.Unmarshal([]byte(cont), &loginReceive)
	if err != nil {
		data.Registered = false
		config.GetLogger().Warnw("数据解析失败",
			"err", err,
		)
		return err
	}
	config.GetLogger().Info("解析注册数据结束")

	config.GetLogger().Info("开始注册")

	//查询用户名是否重复，重复返回错误，否则数据库里插入一条数据
	db.Table("user").Where("userName = ?", loginReceive.UserName).Count(&count)

	//用户名存在时，
	if count != 0 {
		data.Registered = false
		config.GetLogger().Warnw("注册失败",
			"err", errors.New("用户名已存在"),
		)
		return errors.New("用户名已存在")
	}

	//电话号码不能重复
	count = 0
	db.Table("user").Where("userTel = ?", loginReceive.UserTel).Count(&count)

	//号码存在时
	if count != 0 {
		data.Registered = false
		config.GetLogger().Warnw("注册失败",
			"err", errors.New("号码已存在"),
		)
		return errors.New("号码已存在")
	}

	//新建用户，初始化用户数据
	user := new(DBInfo)

	//对用户id进行系列化标识
	ul := uuid.NewV4()
	user.UserID = ul.String()

	//密码进行MD5加密
	tempPwd := md5.Sum([]byte(loginReceive.UserPassword))
	md5str := fmt.Sprintf("%x", tempPwd)
	user.UserPassword = md5str

	user.UserName = loginReceive.UserName
	user.UserNickName = loginReceive.UserNickName
	user.UserSex = loginReceive.UserSex
	user.UserTel = loginReceive.UserTel
	user.UserAddr = loginReceive.UserAddr
	user.UserEmail = loginReceive.UserEmail
	user.QQ = loginReceive.QQ
	user.WX = loginReceive.WX

	user.UserType = 2
	user.UserStatus = 0
	user.UserHeadPortrait = "1"
	user.LoveNum = 1
	user.DesireNum = 3
	user.StoryNum = 2
	user.Time = time.Now().String()

	//数据库中新建一个用户
	if err = db.Table("user").Create(user).Error; err != nil {
		data.Registered = false
		config.GetLogger().Warnw("注册失败",
			"err", err,
		)
		return
	}

	data.Registered = true

	config.GetLogger().Info("注册结束")

	return
}

/**
 * 发送验证码
 */
func (u *User) send(tel string) (err error) {
	data := &u.SecureCodeData
	user := new(SendCode)

	//数据解析
	config.GetLogger().Info("开始解析数据")
	err = json.Unmarshal([]byte(tel), &user)
	if err != nil {
		config.GetLogger().Warnw("登录数据解析失败",
			"err", err.Error,
		)
		return err
	}
	config.GetLogger().Info("解析数据结束")

	config.GetLogger().Info("开始查询与此手机号绑定的相关记录")
	userID := ""
	err = db.Table("user").Where("userTel = ?", user.UserTel).Select("ID").Row().Scan(&userID)
	if err != nil {
		config.GetLogger().Warnw("此手机号未绑定账号",
			"err", err,
		)
		return errors.New("此手机号未绑定账号")
	}
	config.GetLogger().Info("查询与此手机号绑定的相关记录结束")

	//生成6位随机验证码
	config.GetLogger().Info("开始生成6位随机验证码")
	code := utils.Code{}.RandCode()
	config.GetLogger().Info("生成6位随机验证码结束")

	config.GetLogger().Info("开始读取ak")
	//windows
	//fileStr := ".\\ak\\ak.json"
	//linux
	fileStr := "./ak/ak.json"

	f, err := ioutil.ReadFile(fileStr)
	if err != nil {
		fmt.Println("read fail", err)
		config.GetLogger().Warnw("文件读取失败",
			"err", err,
		)
		return
	}

	i := new(ReceiveAK)
	err = json.Unmarshal([]byte(f), &i)
	if err != nil {
		config.GetLogger().Warnw("矩阵数据解析失败",
			"err", err,
		)
		return err
	}
	config.GetLogger().Info("读取ak结束")

	config.GetLogger().Info("开始发送验证码")
	//检查用于发送验证码的手机号是否已经被注册
	client, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", i.AK, i.AKS)
	if err != nil {
		data.Sent = false
		config.GetLogger().Warnw("获取手机验证码失败",
			"err", err,
		)
		return
	}

	request := dysmsapi.CreateSendSmsRequest()
	request.Scheme = "https"

	request.PhoneNumbers = user.UserTel
	request.SignName = "Wall万能墙"
	request.TemplateCode = "SMS_205458618"
	request.TemplateParam = "{code:\"" + code + "\"}"
	//request.TemplateParam = "{code:123456}"

	response, err := client.SendSms(request)
	if err != nil {
		data.Sent = false
		config.GetLogger().Warnw("获取手机验证码失败",
			"err", err,
		)
		return
	}
	fmt.Printf("response is %#v\n", response)

	config.GetLogger().Info("发送验证码结束")
	//redis储存验证码，1分钟
	config.GetRedis().Del(user.UserTel)
	config.GetRedis().Set(user.UserTel, code, 1*time.Minute)

	data.Sent = true

	return
}

/**
 * 验证码验证
 */
func (u *User) verify(cont string) (err error) {
	data := &u.VerifyCodeData

	//接收前端所传数据并解析
	config.GetLogger().Info("开始解析数据")
	user := new(Verify)
	err = json.Unmarshal([]byte(cont), &user)
	if err != nil {
		config.GetLogger().Warnw("登录数据解析失败",
			"err", err.Error,
		)
		return err
	}
	config.GetLogger().Info("解析数据结束")

	//查询绑定的手机号
	config.GetLogger().Info("开始查询与此手机号绑定的用户ID")
	row := db.Table("user").Where("userTel = ?", user.UserTel).Select("ID").Row()
	err = row.Scan(&data.UserID)
	if err != nil {
		data.Verified = false
		config.GetLogger().Warnw("此手机号未绑定",
			"err", err,
		)
		return errors.New("此手机号未绑定")
	}
	config.GetLogger().Info("查询与此手机号绑定的用户ID结束")

	//获取发送验证码时储存在redis中的验证码
	config.GetLogger().Info("开始获取redis中的验证码")
	tempCode, err := config.GetRedis().Get(user.UserTel).Result()
	if err != nil {
		data.Verified = false
		config.GetLogger().Warnw("验证手机验证码失败",
			"err", err,
		)
		return errors.New("获取验证码错误")
	}
	config.GetLogger().Info("获取redis中的验证码结束")

	//校验验证码
	config.GetLogger().Info("开始校验验证码")
	if tempCode != user.UserSecureCode {
		data.Verified = false
		return errors.New("验证码错误")
	} else {
		data.Verified = true
	}
	config.GetLogger().Info("校验验证码结束")
	return
}

//----------------------------------分割线----------------------------------------
func (u *User) GetLoginData(cont string) (err error, data LoginData) {
	config.GetLogger().Info("开始获取登录数据")

	err = u.login(cont)

	data = u.LoginData

	config.GetLogger().Info("获取登录数据结束")

	return
}

func (u *User) GetRegisterData(cont string) (err error, data RegisterData) {
	config.GetLogger().Info("开始获取注册数据")

	err = u.register(cont)

	data = u.RegisterData

	config.GetLogger().Info("获取注册数据结束")

	return
}

func (u *User) GetSecureCodeData(tel string) (err error, data SecureCodeData) {
	config.GetLogger().Info("开始发送手机验证码")

	err = u.send(tel)

	data = u.SecureCodeData

	config.GetLogger().Info("发送手机验证码结束")

	return
}

func (u *User) GetVerifyCodeData(cont string) (err error, data VerifyCodeData) {
	config.GetLogger().Info("开始获取验证手机验证码数据")

	err = u.verify(cont)

	data = u.VerifyCodeData

	config.GetLogger().Info("获取验证手机验证码数据结束")

	return
}
